home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 June / Macworld (1999-06).dmg / Shareware World / Info / For Developers / MacZoop2.0.sea / MacZoop2.0 / Required Classes / ZApplication.cpp < prev    next >
Text File  |  1999-02-24  |  50KB  |  1,866 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZApplication.cpp    -- the application object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "MacZoop.h"
  23. #include    "ProjectSettings.h"
  24. #include    "ZEventHandler.h"
  25. #include    "ZWindow.h"
  26. #include    "ZPrinter.h"
  27. #include    "ZUndoTask.h"
  28.  
  29. #ifdef        USER_DEFAULT_WINDOW_TYPE
  30. #include    HEADER( USER_DEFAULT_WINDOW_TYPE )
  31. #endif
  32.  
  33. #if _USE_NAVIGATION_SERVICES
  34. #include    <Navigation.h>
  35. #endif
  36.  
  37. #include    <StandardFile.h>
  38. #include    <Notification.h>
  39. #include    <dialogs.h>
  40.  
  41. // gApplication is the global application object. There is only one, naturally.
  42.  
  43. ZApplication*    gApplication = NULL;
  44.  
  45. // globals inited by this class
  46.  
  47. ZMenuBar*        gMenuBar = NULL;            // the main menubar object
  48. OSType            gAppSignature;                // the application's signature, obtained from 'BNDL', etc.    
  49. tMacInfo        gMacInfo;                    // common gestalt results
  50. RgnHandle        gUtilRgn = NULL;            // general purpose region, handy as temp variable. Do NOT dispose!
  51. ZPrefsFile*        gPrefsFile = NULL;            // NOT inited unless your application subclass does it!
  52. OSErr            gDragErr = noErr;            // Set if Drag/Drop produced an error
  53.  
  54. // a set of useful colours, available as global RGBColor records
  55.  
  56. RGBColor        gWhite         = {  0xFFFF, 0xFFFF, 0xFFFF };    // white RGB colour
  57. RGBColor        gBlack         = {  0x0000, 0x0000, 0x0000 };    // black RGB colour
  58. RGBColor        gLightGray     = {  0xDDDD, 0xDDDD, 0xDDDD };    // light gray RGB colour
  59. RGBColor        gMidGray     = {  0x7F7F, 0x7F7F, 0x7F7F };    // medium gray RGB colour
  60. RGBColor        gDarkGray     = {  0x5555, 0x5555, 0x5555 };    // dark gray RGB colour
  61. RGBColor        gRed        = {  0xFFFF, 0x0000, 0x0000 };    // solid red RGB colour
  62. RGBColor        gGreen        = {  0x0000, 0xFFFF, 0x0000 };    // solid green RGB colour
  63. RGBColor        gBlue        = {  0x0000, 0x0000, 0xFFFF };    // solid blue RGB colour
  64. RGBColor        gCyan        = {  0x0000, 0xFFFF, 0xFFFF };    // solid cyan RGB colour
  65. RGBColor        gMagenta    = {  0xFFFF, 0x0000, 0xFFFF };    // solid magenta RGB colour
  66. RGBColor        gYellow        = {  0xFFFF, 0xFFFF, 0x0000 };    // solid yellow RGB colour
  67.  
  68. // static functions used by the application object
  69.  
  70. static pascal long     ZGrowFunc( Size bytesShort );
  71. static GrowZoneUPP    gGZFunc = NewGrowZoneProc( ZGrowFunc );
  72.  
  73. #if _USE_NAVIGATION_SERVICES
  74. static pascal void    ZNavEventCallback(     NavEventCallbackMessage cbMessage,
  75.                                         NavCBRecPtr    cbParams,
  76.                                         NavCallBackUserData    cbData );
  77. NavEventUPP        gNavEventHandler = NewNavEventProc( ZNavEventCallback );
  78. #endif
  79.  
  80. extern void        TimerTimer();
  81.  
  82. // note: ZApplication is NEVER instantiated from a stream- to ensure this but keep
  83. // special cases out of the class registry, etc, we jig the construction function
  84. // to simply return gApplication.
  85.  
  86. ZObject*     CF_ZApplication()
  87. {
  88.     return gApplication;
  89. }
  90.  
  91.  
  92. extern ZObject* CF_ZObjectList();
  93.  
  94. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  95.  
  96. ZApplication::ZApplication()
  97.     : ZCommander( NULL )
  98. {
  99.     long    features;
  100.     OSErr    theErr;
  101.     
  102.     classID = CLASS_ZApplication;
  103.     
  104.     gUtilRgn = NewRgn();
  105.     done = FALSE;
  106.     phase = kInitialising;
  107.     zEH = NULL;
  108.     curUndoTask = NULL;
  109.     itsPrinter = NULL;
  110.     splashVisible = FALSE;
  111.     msDepth = 0;
  112.     
  113.     appResRefNum = CurResFile();
  114.     
  115.     // set initial filetypes list to a zero handle
  116.     
  117.     itsFileTypes = (FTypeListHdl) NewHandleClear( sizeof( FTypeList ) - sizeof( OSType ));
  118.         
  119.     shortageFund = NULL;
  120.     memIsShort = FALSE;
  121.     userHasSeenAlert = FALSE;
  122.     
  123.     // check to see if we are running on a colour Mac
  124.     
  125.     theErr = Gestalt( gestaltQuickdrawFeatures, &features );
  126.     gMacInfo.supportsColour = ((theErr == noErr) && (features & 1));
  127.     
  128.     // check for the drag manager
  129.     
  130.     theErr = Gestalt( gestaltDragMgrAttr, &features );
  131.     gMacInfo.hasDragManager = ((theErr == noErr) && (features & 1));
  132.     
  133.     // check for a FPU
  134.     
  135.     theErr = Gestalt( gestaltFPUType, &features );
  136.     gMacInfo.hasFPU = ((theErr == noErr) && ((features & 1) == 0));
  137.     
  138.     // check for applescript
  139.     
  140.     theErr = Gestalt( gestaltAppleEventsAttr, &features );
  141.     gMacInfo.hasAppleEvents = ((theErr == noErr) && (features & 1));
  142.     
  143.     // check for QuickTime™
  144.     
  145.     theErr = Gestalt( gestaltQuickTimeVersion, &features );
  146.     gMacInfo.hasQuickTime = ((theErr == noErr) && (features > 0));
  147.  
  148.     // check for ICM
  149.     
  150.     theErr = Gestalt( gestaltCompressionMgr, &features );
  151.     gMacInfo.hasImgCompressionMgr = (theErr == noErr);
  152.  
  153.     // check for appearance manager
  154.     
  155.     #if APPEARANCE_MGR_AWARE
  156.         theErr = Gestalt( gestaltAppearanceAttr, &features );
  157.         gMacInfo.hasAppearanceMgr = (( theErr == noErr ) && ( features & 1 ));
  158.         
  159.         #if __powerc
  160.         if ( gMacInfo.hasAppearanceMgr )
  161.             gMacInfo.hasAppearanceMgr = ((long)  CreateRootControl != kUnresolvedCFragSymbolAddress );
  162.         #endif
  163.     
  164.     #else
  165.         gMacInfo.hasAppearanceMgr = FALSE;
  166.     
  167.     #endif
  168.  
  169.     // what is the system version?
  170.     
  171.     theErr = Gestalt( gestaltSystemVersion, &features );
  172.     gMacInfo.systemVersion = LoWord( features );
  173.     
  174.     // check for navigation services:
  175.     
  176.     #if _USE_NAVIGATION_SERVICES
  177.     if ( gMacInfo.systemVersion >= 0x0755 )
  178.         gMacInfo.hasNavigationServices = NavServicesAvailable();
  179.     #else
  180.         gMacInfo.hasNavigationServices = FALSE;
  181.     #endif
  182.     
  183.     // check for contextual menus:
  184.     
  185.     if ( gMacInfo.systemVersion >= 0x0800 )
  186.         gMacInfo.hasContextualMenus = TRUE;
  187.     else
  188.         gMacInfo.hasContextualMenus = FALSE;
  189.         
  190.     // initialise the animating cursors, and set the
  191.     // animated watch cursor going.
  192.     
  193.     AppCursorInit();
  194.     gApplication = this;
  195. }
  196.  
  197. /*--------------------------------***  DESTRUCTOR  ***---------------------------------*/
  198.  
  199.  
  200. ZApplication::~ZApplication()
  201. {
  202. #if __ZPREFSFILE__
  203.     if ( gPrefsFile )
  204.         ForgetObject( gPrefsFile );
  205. #endif
  206.     
  207.     if ( gMenuBar )    
  208.         ForgetObject( gMenuBar );
  209.     
  210. #if _SLOW_BUT_SURE_DESTRUCTION
  211.     
  212.     // this stuff is destructed only if the above is set to ON, but note that
  213.     // if OFF, the app will quit normally, and quickly, relying on the heap
  214.     // being freed in one go when the app exits to shell. This is NOT a memory
  215.     // leak!!! Since all objects are allocated in the heap, the memory is freed
  216.     // when the heap is freed. However, the destructors are not called in this case.
  217.     
  218.     if ( gClipboard )
  219.         ForgetObject( gClipboard );
  220.     
  221.     if ( gWindowManager )
  222.         ForgetObject( gWindowManager );
  223.     
  224.     if ( zEH )
  225.         ForgetObject( zEH );
  226.         
  227.     if ( itsPrinter )
  228.         ForgetObject( itsPrinter );
  229.         
  230.     if ( curUndoTask )
  231.         ForgetObject( curUndoTask );
  232.         
  233.     if ( itsFileTypes )
  234.         DisposeHandle((Handle) itsFileTypes);
  235.     
  236.     if ( shortageFund )
  237.         DisposeHandle( shortageFund );
  238.         
  239.     DisposeRgn( gUtilRgn );
  240.     AppCursorFree();
  241.     
  242. #endif
  243.     
  244.     StopCursorAnimation();
  245. }
  246.  
  247.  
  248. /*--------------------------------***  INITMACZOOP  ***---------------------------------*/
  249. /*    
  250.  
  251. Initialises the application, makes the event handler object and the menubar
  252.  
  253. ----------------------------------------------------------------------------------------*/
  254.  
  255. void        ZApplication::InitMacZoop( const short numMasterBlocks )
  256. {
  257.     if ( phase == kInitialising )
  258.     {
  259.         // init the mac toolbox, memory mangler etc.
  260.         
  261.         RegisterClasses();
  262.         InitMacApplication( numMasterBlocks );
  263.         
  264.         // create the memory shortage fund
  265.         
  266.         FailNIL( shortageFund = NewHandle( kShortageFundSize ));
  267.         SetGrowZone( gGZFunc );
  268.         
  269.         SetWatchCursor();
  270.         
  271.         // make the helper objects
  272.         
  273.         MakeHelpers();
  274.     
  275.         // make the clipboard object
  276.         
  277.         MakeClipboard();
  278.         
  279.         // read any prefs that the user may have set up (default does nothing). A typical
  280.         // thing to do here is to simply instantiate a ZPrefsFile object and assign it to
  281.         // <gPrefsFile>. You may also want to open/read the file! (use of data or resource
  282.         // fork is up to you, so ZPrefsFile does not automatically perform the open step).
  283.         
  284.         ReadPrefs();
  285.         ShowSplash();
  286.         
  287.         // initialise menubar and make printer object
  288.         
  289.         InitMenuBar();
  290.         MakePrinter();
  291.         
  292.         // preload the navigation services if required, to make use of these faster later on.
  293.         
  294.         #if _USE_NAVIGATION_SERVICES
  295.         if ( gMacInfo.hasNavigationServices )
  296.             FailOSErr( NavLoad());
  297.         #endif
  298.         
  299.         // call user-function as last part of initialisation- default
  300.         // does nothing but can be overridden to do further set up.
  301.         
  302.         StartUp();
  303.         
  304.         // record depth of main screen
  305.         
  306.         msDepth = GetMainScreenDepth();
  307.         
  308.         // update the menubar- note that this is not drawn until StartUp completes,
  309.         // since we allow the programmer the flexibility to use StartUp to create & install
  310.         // dynamic menus, etc. if they want.
  311.         
  312.         gMenuBar->UpdateMenuBar();
  313.         
  314.         // the cursor is not reset here- we let the main event loop do that so that if
  315.         // events are initially available, the cursor keeps right on animating until
  316.         // the user gets a chance to do anything.
  317.     }
  318. }
  319.  
  320. /*-----------------------------***  INITMACAPPLICATION  ***-----------------------------*/
  321. /*    
  322.  
  323. Initialises the mac toolbox and memory manager
  324.  
  325. ----------------------------------------------------------------------------------------*/
  326.  
  327.     
  328. void        ZApplication::InitMacApplication( const short numMasterBlocks )
  329. {
  330.     // chant the "Macintosh mantra"...
  331.     
  332.     InitGraf( &qd.thePort );
  333.     InitFonts();
  334.     InitWindows();
  335.     InitMenus();
  336.     TEInit();
  337.     InitDialogs( NULL );
  338.     
  339.     // clear out the event queue in case any stray clicks or keypresses are left there
  340.     
  341.     FlushEvents( everyEvent, 0 );
  342.  
  343.     // see if the program can run on this Mac- if not, we show an alert and exit straight away
  344.     
  345.     if (! CheckCanRun())
  346.     {
  347.         StopCursorAnimation();
  348.         (void) Alert( kCantRunAlertID, NULL );
  349.         ExitToShell();
  350.     }    
  351.     else
  352.     {
  353.         // give yourself enough memory. For a bigger app, you may need to call MoreMasters a few
  354.         // more times. The parameter to this method sets the number of times MoreMasters is
  355.         // called, defaulting to 8, which gives 8 x 64 = 512 handles.
  356.         
  357.         MaxApplZone();
  358.         
  359.         short n = numMasterBlocks;
  360.         
  361.         while( n-- )
  362.             MoreMasters();
  363.             
  364.         // if we want appearance, register the app:
  365.         
  366.     #if APPEARANCE_MGR_AWARE
  367.         
  368.         if ( gMacInfo.hasAppearanceMgr )
  369.             FailOSErr( RegisterAppearanceClient());
  370.     
  371.     #endif
  372.             
  373.         // set up <gAppSignature>, either from BNDL resource, or from constant according
  374.         // to the user's project settings.
  375.         
  376.     #if USE_SIGNATURE_FROM_BNDL
  377.         
  378.         OSType**    bndlHand = (OSType**) GetResource( 'BNDL', 128 );
  379.         
  380.         if ( bndlHand )
  381.         {
  382.             gAppSignature = **bndlHand;
  383.             ReleaseResource((Handle) bndlHand );
  384.             
  385.             #if CHECK_FREF_RESOURCE_TYPES
  386.             
  387.             // first look for an 'open' resource ID=128. If there is one, we use it in
  388.             // preference to the FREF's, since there is a slightly different meaning. An 'open'
  389.             // resource can be treated as a list of OSTypes if you ignore the first 8 bytes.
  390.             
  391.             bndlHand = (OSType**) GetResource( 'open', 128 );
  392.             
  393.             if ( bndlHand )
  394.             {
  395.                 // we have an 'open' resource, so just copy the data (ignoring first 8 bytes)
  396.                 // to the file types list. Warning: This technique does not check for duplicates,
  397.                 // either in the resource or in the types list.
  398.                 
  399.                 long    bc = GetHandleSize((Handle) bndlHand );
  400.                 
  401.                 SetHandleSize((Handle) itsFileTypes, bc );
  402.                 FailMemError();
  403.                 
  404.                 BlockMoveData((Ptr) *bndlHand, (Ptr) *itsFileTypes, bc );
  405.                 ReleaseResource((Handle) bndlHand );
  406.             }
  407.             else
  408.             {
  409.                 // scan the 'FREF' resources and build the <itsFileTypes> list. We do NOT add
  410.                 // types of 'APPL', 'cdev', 'INIT', or 'rdev'- if you want to display such
  411.                 // files in the Open dialog, you have to call AddFileType() for these types directly.
  412.                 // This is a feature to prevent weird behaviour in the typical case.
  413.                 
  414.                 // how many 'FREF's do we have?
  415.                 
  416.                 short    i, fc = Count1Resources( 'FREF' );
  417.                 
  418.                 for( i = 1; i <= fc; i++ )
  419.                 {
  420.                     bndlHand = (OSType**) GetIndResource( 'FREF', i );
  421.                 
  422.                     if ( bndlHand )
  423.                     {
  424.                         // check if this is one of our 'forbidden' types:
  425.                         
  426.                         if ( **bndlHand != 'APPL'    &&
  427.                              **bndlHand != 'APPC'    &&
  428.                              **bndlHand != 'APPD'    &&
  429.                              **bndlHand != 'cdev'    &&
  430.                              **bndlHand != 'rdev'    &&
  431.                              **bndlHand != 'INIT' )
  432.                             AddFileType( **bndlHand );
  433.                         
  434.                         ReleaseResource((Handle) bndlHand );
  435.                     }
  436.                 }
  437.             }
  438.             
  439.             #endif    
  440.         }
  441.         else
  442.             gAppSignature = kUnknownSignature;
  443.     #else
  444.         gAppSignature = kApplicationSignature;
  445.     #endif
  446.     
  447.         (*itsFileTypes)->appSignature = gAppSignature;
  448.     }
  449. }
  450.  
  451. /*--------------------------------***  CHECKCANRUN  ***---------------------------------*/
  452. /*    
  453.  
  454. Examine the machine environment to see if this will run on this Mac. By default, it can
  455. on System 7 or later.
  456.  
  457. ----------------------------------------------------------------------------------------*/
  458.  
  459. Boolean        ZApplication::CheckCanRun()
  460. {
  461.     // Returning FALSE will cause the program to
  462.     // immediately show an alert and quit.
  463.     
  464.     // by default, we can run on any Mac with System 7.0 or later.
  465.     
  466.     return( gMacInfo.systemVersion >= 0x0700 );    
  467. }
  468.  
  469. #pragma mark -
  470. /*----------------------------------***  GETNAME  ***-----------------------------------*/
  471. /*    
  472. Get the user-visible name of the application, as seen in the Finder. This works even if
  473. the user has renamed the app, since it finds the filename.
  474. ----------------------------------------------------------------------------------------*/
  475.  
  476.  
  477. void        ZApplication::GetName( Str255 appName )
  478. {
  479.     CopyPString( LMGetCurApName(), appName );
  480. }
  481.  
  482. /*------------------------------------***  RUN  ***-------------------------------------*/
  483. /*    
  484.  
  485. Fetch events and handle them until the user quits. The very first time this is entered,
  486. phase is set to kInitialising, so we first call RunFirstTask(), which is your ideal
  487. opportunity to create the fixed user interface, remove splash screens, etc. This is a
  488. better place than StartUp(), since you are protected by the standard error handling.
  489. An exception from StartUp() will fatally abort app launch, here you will continue.
  490. ----------------------------------------------------------------------------------------*/
  491.  
  492. void        ZApplication::Run()
  493. {
  494.     // runs the show by asking the event object to get events and handle them. This goes on
  495.     // forever until done is set to TRUE.
  496.     
  497.     while(! done)
  498.     {
  499.         try
  500.         {
  501.             if ( phase == kInitialising )
  502.             {
  503.                 phase = kRunning;
  504.                 RunFirstTask();
  505.             }
  506.             
  507.             // repeatedly get an event, handle an event
  508.             
  509.             Process1Event();
  510.             
  511.             // deal with the memory shortage situation, if one has arisen as
  512.             // a result of the last event.
  513.             
  514.             CheckLowMemory();
  515.             
  516.             // check for a drag error resulting from the last drag (if any)
  517.             
  518.             if ( gDragErr )
  519.             {
  520.                 HandleError( gDragErr );
  521.                 gDragErr = noErr;
  522.             }
  523.         }
  524.         catch( OSErr theErr )
  525.         {
  526.             // if here, an exception was thrown. Deal with the error by calling the
  527.             // application's HandleError() method.
  528.             
  529.             StopCursorAnimation();
  530.             HandleError( theErr );
  531.             
  532.             // the buck stops here- no exceptions will be thrown beyond this point.
  533.         }
  534.         catch(...)
  535.         {
  536.             // catch anything that was thrown that is not an OSErr. This may happen if the runtime
  537.             // lib threw an exception for operator new, etc. At least in this case we can try to keep
  538.             // running.
  539.             
  540.             StopCursorAnimation();
  541.             HandleError( kRuntimeLibException );
  542.         }
  543.         // stop any animating cursors. This means that a lengthy process need
  544.         // only set the cursor going and can then forget about it. When the
  545.         // app resumes handling events, it will be automatically cancelled.
  546.         
  547.         StopCursorAnimation();
  548.     }
  549.     
  550.     done = TRUE;
  551.     phase = kQuitting;
  552. }
  553.  
  554.  
  555. /*-----------------------------***  CHECKLOWMEMORY  ***---------------------------------*/
  556. /*    
  557. check if a low memory situation has arisen. If so, inform the user and manage the re-
  558. plenishment of the shortage fund.
  559. ----------------------------------------------------------------------------------------*/
  560.  
  561. void        ZApplication::CheckLowMemory()
  562. {
  563.     if ( memIsShort )
  564.     {
  565.         // some of the shortage fund was used. Try to replenish it:
  566.         
  567.         memIsShort = FALSE;
  568.         
  569.         Handle temp = NewHandle( kShortageFundSize );
  570.         
  571.         // if that resets memIsShort, then the grow zone func was called, so we
  572.         // are not in the clear yet. However, if the grow zone func wasn't
  573.         // called, then we can safely get rid of that handle and replace it with
  574.         // this one
  575.         
  576.         if ( memIsShort )
  577.         {
  578.             if ( temp )
  579.                 DisposeHandle( temp );
  580.             
  581.             // couldn't replenish the fund, so if the user hasn't seen the
  582.             // warning yet, show it now.
  583.             
  584.             if (! userHasSeenAlert)
  585.             {
  586.                 StopCursorAnimation();
  587.                 (void) NotifyAlert( kMemoryLowAlertID );
  588.                 userHasSeenAlert = TRUE;
  589.             }
  590.             
  591.             // if memIsShort is TRUE, it affects UpdateMenus such that New and Open are
  592.             // greyed out. This is an attempt to stop the user creating things that will
  593.             // eat up even more memory. You might want to use the same technique for commands
  594.             // of your own that may allocate lots of memory. For this reason, memIsShort is
  595.             // a public member.
  596.         }
  597.         else
  598.         {
  599.             // fund replenished, so get rid of any remaining fund and replace it
  600.             // with the newly allocated shortage fund.
  601.             
  602.             DisposeHandle( shortageFund );
  603.             shortageFund = temp;
  604.             userHasSeenAlert = FALSE;
  605.         }
  606.     }
  607. }
  608.  
  609.  
  610. /*------------------------------***  MEMORYSHORTAGE  ***--------------------------------*/
  611. /*    
  612.  
  613. called from the growzone proc when memory needs to be freed. This releases some or all
  614. of the shortage fund, but you can override it to make additional sacrifices if need be.
  615. ----------------------------------------------------------------------------------------*/
  616.  
  617. Boolean        ZApplication::MemoryShortage( const Size bytesShort )
  618. {
  619.     // this is called when the memory manager gets into dire straits. We can free some or all
  620.     // of our emergency fund to satisfy the request. If we succeed, we return TRUE, else FALSE.
  621.     
  622.     Size    fundSize = 0;
  623.     Handle    gzHandle;
  624.     
  625.     // get the handle the mem manager is dealing with at the moment. This is important since
  626.     // this might be the shortage fund itself. If it is, we can't resize it, so we really
  627.     // are in deep do-do. In this case, we flag memIsShort and hope the user will not ignore
  628.     // the message!
  629.     
  630.     gzHandle = GZSaveHnd();
  631.     
  632.     if ( gzHandle != shortageFund )
  633.     {
  634.         fundSize = GetHandleSize( shortageFund );
  635.         
  636.         // release all or some of the memory to try and satisfy the request
  637.         
  638.         if ( fundSize <= bytesShort )
  639.             SetHandleSize( shortageFund, 0 );
  640.         else
  641.             SetHandleSize( shortageFund, fundSize - bytesShort );
  642.     }
  643.     // flag the shortage so we can inform the user
  644.     
  645.     memIsShort = TRUE;
  646.     
  647.     // did we actually manage to free the requested amount?
  648.     
  649.     return( fundSize > bytesShort );
  650. }
  651.  
  652.  
  653. /*------------------------------***  PROCESS1EVENT  ***---------------------------------*/
  654. /*    
  655. get an event, dispatch an event, get an event, dispatch...
  656. ----------------------------------------------------------------------------------------*/
  657.  
  658. void        ZApplication::Process1Event()
  659. {
  660.     EventRecord        theEvent;
  661.     
  662.     zEH->GetAnEvent( &theEvent );
  663.     zEH->DispatchAnEvent( &theEvent );
  664.     
  665.     // timer queue is iterated at the end of handling an event
  666.     
  667.     TimerTimer();
  668. }
  669.  
  670.  
  671. /*------------------------------***  PROCESS1EVENT  ***---------------------------------*/
  672. /*    
  673. dispatch an event that was fetched externally, for example by a library such as Nav
  674. Services.
  675. ----------------------------------------------------------------------------------------*/
  676.  
  677. void        ZApplication::Process1Event( EventRecord* anExternalEvent )
  678. {
  679.     zEH->DispatchAnEvent( anExternalEvent );
  680.     
  681.     TimerTimer();
  682. }
  683.  
  684.  
  685. /*----------------------------***  PROCESSALLEVENTS  ***--------------------------------*/
  686. /*    
  687. process all pending events, until a null event arrives
  688. ----------------------------------------------------------------------------------------*/
  689.  
  690. void        ZApplication::ProcessAllEvents()
  691. {
  692.     EventRecord        theEvent;
  693.     
  694.     do
  695.     {
  696.         zEH->GetAnEvent( &theEvent );
  697.         zEH->DispatchAnEvent( &theEvent );
  698.         
  699.         // timer queue is iterated at the end of handling an event
  700.         
  701.         TimerTimer();
  702.     }
  703.     while( theEvent.what != nullEvent );
  704. }
  705.  
  706.  
  707. /*-----------------------------***  GETCURRENTEVENT  ***--------------------------------*/
  708. /*
  709. return the current event in progress, with FALSE if it was a null event, else TRUE.    
  710. ----------------------------------------------------------------------------------------*/
  711.  
  712. Boolean        ZApplication::GetCurrentEvent( EventRecord* anEvent )
  713. {
  714.     zEH->GetLatestEvent( anEvent );
  715.     
  716.     return( anEvent->what != nullEvent );
  717. }
  718.  
  719.  
  720. /*--------------------------------***  GETCLICKS  ***-----------------------------------*/
  721. /*    
  722. return the number of clicks counted by the event handler in the same place. Returns 1 for
  723. single click, 2 for double, 3 for triple, etc.
  724. ----------------------------------------------------------------------------------------*/
  725.  
  726. short        ZApplication::GetClicks()
  727. {
  728.     return zEH->GetClicks();
  729. }
  730.  
  731.  
  732. /*-------------------------------***  INBACKGROUND  ***---------------------------------*/
  733. /*    
  734. return TRUE if the application is in the background, FALSE in foreground.
  735. ----------------------------------------------------------------------------------------*/
  736.  
  737. Boolean        ZApplication::InBackground()
  738. {
  739.     return zEH->InBackground();
  740. }
  741.  
  742.  
  743. /*-----------------------------------***  QUIT  ***-------------------------------------*/
  744. /*    
  745.  
  746. close all of the windows. If successful, delete the application and return TRUE
  747.  
  748. ----------------------------------------------------------------------------------------*/
  749.  
  750. Boolean        ZApplication::Quit()
  751. {
  752.     Boolean wereDone = done;
  753.     
  754.     if ( phase == kQuitting )
  755.     {
  756.         CloseAll();
  757.         
  758.         // copy <done> locally to avoid reading bad ref after class deleted
  759.         
  760.         wereDone = done;
  761.         
  762.         // the Quit can be abandoned by resetting <done> to FALSE. If this
  763.         // has not occurred, then truly say goodbye.
  764.         
  765.         if ( done )
  766.         {
  767.             #if _USE_NAVIGATION_SERVICES
  768.             if ( gMacInfo.hasNavigationServices )
  769.                 NavUnload();
  770.             #endif
  771.             
  772.             #if APPEARANCE_MGR_AWARE
  773.             if ( gMacInfo.hasAppearanceMgr )
  774.                 (void) UnregisterAppearanceClient();
  775.             #endif
  776.             
  777.             ShutDown();
  778.             ForgetThis();
  779.         }
  780.     }
  781.     return wereDone;
  782. }
  783.  
  784.  
  785. /*-------------------------------***  REQUESTQUIT  ***----------------------------------*/
  786. /*    
  787.  
  788. ask the application to quit. This is called by choosing Quit from the File menu, for example.
  789.  
  790. ----------------------------------------------------------------------------------------*/
  791.  
  792.  
  793. void        ZApplication::RequestQuit()
  794. {
  795.     done = TRUE;
  796. }
  797.  
  798. /*----------------------------***  HANDLEAPPLEEVENT  ***--------------------------------*/
  799. /*    
  800. Handle the four required apple events. If you override this to handle your own apple
  801. events, be sure to call the inherited method for everything else.
  802. ----------------------------------------------------------------------------------------*/
  803.  
  804. void        ZApplication::HandleAppleEvent(    AEEventClass aeClass, AEEventID aeID,
  805.                                             AppleEvent* aeEvt, AppleEvent* reply )
  806. {
  807.     if ( aeClass == kCoreEventClass )
  808.     {
  809.         FSSpec        aFile;
  810.         AEDescList    docList;
  811.         long        i, n;
  812.         AEKeyword    keyWrd;
  813.         DescType    retType;
  814.         Size        actualSize;
  815.         FInfo        fi;
  816.         
  817.         switch ( aeID )
  818.         {
  819.             case kAEReopenApplication:
  820.                 if ( GetFrontWindow())
  821.                     break;
  822.                 // fall through to normal open app event case if there are no windows:
  823.             case kAEOpenApplication:
  824.                 #if MAKE_UNTITLED_STARTUP_WINDOW
  825.                 OpenNewWindowType( kDefaultWindowType );
  826.                 #endif
  827.                 break;
  828.             
  829.             case kAEOpenDocuments:
  830.                 // do not handle this event if a modal dialog is up
  831.                 
  832.                 if ( gWindowManager->IsDialog( GetFrontWindow()))
  833.                     FailOSErr( kModalDialogOnScreenErr );
  834.             
  835.                 FailOSErr( AEGetParamDesc( aeEvt, keyDirectObject, typeAEList, &docList ));    
  836.                 FailOSErr( AECountItems( &docList, &n ));
  837.                 
  838.                 // get each document and open it
  839.                 try
  840.                 {
  841.                     for (i = 1; i <= n; i++)
  842.                     {
  843.                         FailOSErr( AEGetNthPtr( &docList,
  844.                                                 i, 
  845.                                                 typeFSS, 
  846.                                                 &keyWrd,
  847.                                                 &retType, 
  848.                                                 &aFile, 
  849.                                                 sizeof( FSSpec ), 
  850.                                                 &actualSize ));
  851.                         
  852.                         FailOSErr( FSpGetFInfo( &aFile, &fi ));
  853.                         
  854.                         // open the file into a window and select it, provided
  855.                         // it really is one we can open. If the file is a prefs file, call up
  856.                         // the kDoPreferences command:
  857.                         
  858.                         if ( fi.fdType == 'pref' )
  859.                             HandleCommand( kCmdDoPreferences );
  860.                         else
  861.                         {
  862.                             if ( CanOpenFileType( fi.fdType ))
  863.                                 OpenFile( aFile, fi.fdType, ( fi.fdFlags & kIsStationery ) == kIsStationery );
  864.                         }
  865.                     }
  866.                 }
  867.                 catch( OSErr err )
  868.                 {
  869.                     AEDisposeDesc( &docList );
  870.                     
  871.                     throw err;
  872.                 }
  873.                 FailOSErr( AEDisposeDesc( &docList ));
  874.                 break;
  875.             
  876.             case kAEPrintDocuments:
  877.                 if ( gWindowManager->IsDialog( GetFrontWindow()))
  878.                     FailOSErr( kModalDialogOnScreenErr );
  879.             
  880.                 FailOSErr( AEGetParamDesc( aeEvt, keyDirectObject, typeAEList, &docList ));    
  881.                 FailOSErr( AECountItems( &docList, &n ));
  882.                 
  883.                 // ask the application to show the page setup dialog
  884.                 
  885.                 if ( n > 0 )
  886.                     DoPageSetup();
  887.                 
  888.                 // get each document passed by the finder
  889.                 
  890.                 try
  891.                 {
  892.                     for (i = 1; i <= n; i++)
  893.                     {
  894.                         FailOSErr( AEGetNthPtr( &docList,
  895.                                                 i, 
  896.                                                 typeFSS, 
  897.                                                 &keyWrd,
  898.                                                 &retType, 
  899.                                                 &aFile, 
  900.                                                 sizeof( FSSpec ), 
  901.                                                 &actualSize ));
  902.                         
  903.                         FailOSErr( FSpGetFInfo( &aFile, &fi ));
  904.                         
  905.                         // open the file into a window and select it
  906.                         
  907.                         if ( CanOpenFileType( fi.fdType ))
  908.                         {
  909.                             ZWindow* zw;
  910.                             
  911.                             zw = OpenFile( aFile, fi.fdType, ( fi.fdFlags & kIsStationery ) == kIsStationery );
  912.                         
  913.                             // update the window (not strictly needed, but looks better)
  914.                         
  915.                             zw->PerformUpdate();
  916.                         
  917.                             // ask the application to print the document
  918.                         
  919.                             DoPrint();
  920.                         
  921.                             // that done, we can close the window and move on to the next
  922.                         
  923.                             zw->Close( GetPhase());
  924.                         }
  925.                     }
  926.                 }
  927.                 catch( OSErr err )
  928.                 {
  929.                     AEDisposeDesc( &docList );
  930.                     
  931.                     throw err;
  932.                 }
  933.                 
  934.                 FailOSErr( AEDisposeDesc( &docList ));
  935.                 break;
  936.             
  937.             case kAEQuitApplication:
  938.                 RequestQuit();
  939.                 break;
  940.             
  941.             default:
  942.                 ZCommander::HandleAppleEvent( aeClass, aeID, aeEvt, reply );
  943.                 break;    
  944.         }
  945.     }
  946.     else
  947.         ZCommander::HandleAppleEvent( aeClass, aeID, aeEvt, reply );
  948. }
  949.  
  950. /*-------------------------------***  HANDLEERROR  ***----------------------------------*/
  951. /*    
  952. display an alert indicating the error (some errors do nothing, likewise noErr is ignored)
  953. ----------------------------------------------------------------------------------------*/
  954.  
  955. void        ZApplication::HandleError( OSErr theErr )
  956. {
  957.     // handles the error passed by displaying an alert. This is called by the exception
  958.     // handler for the application, but you can call it at any time. Some errors are "silent"
  959.     // in that the exception does not result in a message. These include userCanceled, kSilent
  960.     // Err, and aeEventNotHandled. Override this if you want to handle errors differently.
  961.     
  962.     gMenuBar->SetTitleHilite( 0, FALSE );
  963.     
  964.     if ( theErr != userCanceledErr &&
  965.          theErr != kSilentErr       &&
  966.          theErr != noErr            &&
  967.          theErr != errAEEventNotHandled )
  968.     {
  969.         StringHandle    errExpH;    
  970.         Str255            errMsgStr;
  971.         Str31            errExplStr;
  972.         Str15            errIDStr;
  973.         
  974.         gMenuBar->ShowHideMenuBar( MBAR_SHOW );
  975.  
  976.         NumToString( theErr, errIDStr );
  977.         
  978.         // try to build a meaningful error message by looking for an 'Estr'
  979.         // resource with the same iD as the error. If found, this is concatenated
  980.         // onto the generic error stub and displayed. If not found, the default
  981.         // explanation "an error occurred" is used.
  982.         
  983.         GetIndString( errMsgStr, 128, 10 );
  984.         
  985.         errExpH = (StringHandle) GetResource( 'Estr', theErr );
  986.         
  987.         if ( errExpH )
  988.         {
  989.             ConcatPStrings( errMsgStr, *errExpH );     
  990.             ReleaseResource((Handle) errExpH );
  991.         }
  992.         else
  993.         {
  994.             GetIndString( errExplStr, 128, 11 );
  995.             ConcatPStrings( errMsgStr, errExplStr );
  996.         }
  997.         
  998.         ParamText( errIDStr, errMsgStr, NULL, NULL );
  999.         (void) NotifyAlert( kExceptionAlertID, ntMinimalAlert );
  1000.     }
  1001. }
  1002.  
  1003.  
  1004. /*------------------------***  WAITAPPLICATIONFOREGROUND  ***---------------------------*/
  1005. /*    
  1006. handle events until the application is not in the background. Used by NotifyAlert().
  1007. ----------------------------------------------------------------------------------------*/
  1008.  
  1009. void        ZApplication::WaitApplicationForeground()
  1010. {
  1011.     while( InBackground())
  1012.         Process1Event();
  1013. }
  1014.  
  1015.  
  1016. #pragma mark -
  1017.  
  1018. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  1019. /*    
  1020.  
  1021. Handle commands (menu items) that apply to the application as a whole, like Quit.
  1022. ----------------------------------------------------------------------------------------*/
  1023.  
  1024. void        ZApplication::HandleCommand( const long aCmd )
  1025. {
  1026.     // handle commands at the application level. This includes quit, new, open, etc.
  1027.     
  1028.     FSSpec        aFile;
  1029.     OSType        anFType;
  1030.     FInfo        fi;
  1031.     
  1032.     switch( aCmd )
  1033.     {
  1034.         case kCmdAbout:
  1035.             AboutBox();
  1036.             break;
  1037.         
  1038.         case kCmdNew:
  1039.             OpenNewWindowType( kDefaultWindowType );    // open a new "untitled" window
  1040.             break;
  1041.         
  1042.         case kCmdOpen:
  1043.             if ( PickFile( &aFile, &anFType ))            // choose a file
  1044.             {
  1045.                 // is it a stationery (template) file?
  1046.                 
  1047.                 FSpGetFInfo( &aFile, &fi );
  1048.                 OpenFile( aFile, anFType, ( fi.fdFlags & kIsStationery ) == kIsStationery );            // open the file into a window
  1049.             }
  1050.             break;
  1051.         
  1052.         case kCmdQuit:
  1053.             RequestQuit();                            // the app should now quit
  1054.             break;
  1055.         
  1056.         case kCmdPageSetup:
  1057.             DoPageSetup();
  1058.             break;
  1059.         
  1060.         case kCmdPrint:
  1061.             DoPrint();
  1062.             break;
  1063.         
  1064.         case kCmdUndo:
  1065.             if ( curUndoTask )    // undo item available?
  1066.             {
  1067.                 SetWatchCursor();
  1068.                 if (curUndoTask->IsUndone())        // undo or redo?
  1069.                     curUndoTask->Redo();            // redo the task
  1070.                 else
  1071.                     curUndoTask->Undo();            // undo the task
  1072.             }
  1073.             break;
  1074.             
  1075.         case kCmdDoPreferences:
  1076.             DoPreferences();
  1077.             break;
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  1083.  
  1084. void        ZApplication::HandleCommand( const short menuID, const short itemID )
  1085. {
  1086.     GrafPtr        savePort;
  1087.     Str255        daName;
  1088.     
  1089.     if ( menuID == kAppleMenuID &&
  1090.          itemID > 2 )
  1091.     {
  1092.         // open desk accessories.
  1093.         GetMenuItemText( GetMenuHandle( menuID ), itemID, daName );
  1094.         GetPort( &savePort );
  1095.         OpenDeskAcc( daName );
  1096.         SetPort( savePort );
  1097.     }
  1098. }
  1099.  
  1100.  
  1101. /*-------------------------------***  UPDATEMENUS  ***----------------------------------*/
  1102. /*    
  1103.  
  1104. enable the menu commands that the app can handle at the moment.
  1105.  
  1106. ----------------------------------------------------------------------------------------*/
  1107.  
  1108. void    ZApplication::UpdateMenus()
  1109. {
  1110.     // enable the menu commands that pertain to the application. This includes "New",
  1111.     // "Quit" and "About" amongst others
  1112.     
  1113.     // apple menu
  1114.     
  1115.     gMenuBar->EnableCommand( kCmdAbout );
  1116.         
  1117.     // file menu
  1118.     
  1119.     // if memory is currently short, do not enable new or open, since those are the
  1120.     // commands that are likely to allocate a lot more memory, which we do not have.
  1121.     
  1122.     if (! memIsShort)
  1123.     {
  1124.         gMenuBar->EnableCommand( kCmdNew );
  1125.         gMenuBar->EnableCommand( kCmdOpen );
  1126.     }
  1127.     gMenuBar->EnableCommand( kCmdQuit );
  1128.         
  1129.     // enable the printing items if there is a printer and the front window
  1130.     // supports printing.
  1131.     
  1132.     if ( itsPrinter )
  1133.     {
  1134.         gMenuBar->EnableCommand( kCmdPageSetup );
  1135.     
  1136.         ZWindow*    fWindow = GetFrontWindow();
  1137.         
  1138.         if (fWindow && fWindow->IsPrintable())
  1139.             gMenuBar->EnableCommand( kCmdPrint );
  1140.     }    
  1141.     
  1142.     // edit:
  1143.     
  1144.     UpdateUndo();
  1145.     gMenuBar->EnableCommand( kCmdDoPreferences );
  1146. }
  1147.  
  1148.  
  1149. /*-------------------------------***  DOPAGESETUP  ***----------------------------------*/
  1150. /*
  1151. handle the Page Setup command    
  1152. ----------------------------------------------------------------------------------------*/
  1153.  
  1154. void    ZApplication::DoPageSetup()
  1155. {
  1156.     if ( itsPrinter )
  1157.     {
  1158.         gWindowManager->Deactivate();
  1159.         itsPrinter->PageSetUp();
  1160.         gWindowManager->Activate();
  1161.     }
  1162. }
  1163.  
  1164. /*----------------------------------***  DOPRINT  ***-----------------------------------*/
  1165. /*
  1166. handle the Print command    
  1167. ----------------------------------------------------------------------------------------*/
  1168.  
  1169. void    ZApplication::DoPrint()
  1170. {
  1171.     if ( itsPrinter )
  1172.     {
  1173.         ZWindow*    aWindow = GetFrontWindow();
  1174.         
  1175.         gWindowManager->Deactivate();
  1176.         itsPrinter->Print( aWindow );
  1177.         gWindowManager->Activate();
  1178.     }
  1179. }
  1180.  
  1181.  
  1182. /*---------------------------------***  ABOUTBOX  ***-----------------------------------*/
  1183. /*    
  1184. display the application's about box
  1185. ----------------------------------------------------------------------------------------*/
  1186.  
  1187. void    ZApplication::AboutBox()
  1188. {
  1189.     gWindowManager->DeactivateForDialog( kAboutBoxID, TRUE );
  1190.     (void) Alert( kAboutBoxID, NULL );
  1191.     gWindowManager->Activate();
  1192. }
  1193.  
  1194.  
  1195. /*----------------------------------***  SETTASK  ***-----------------------------------*/
  1196. /*    
  1197. update the current global undo task
  1198. ----------------------------------------------------------------------------------------*/
  1199.  
  1200. void    ZApplication::SetTask( ZUndoTask* aTask )
  1201. {
  1202.     if ( curUndoTask )
  1203.         ForgetObject( curUndoTask );
  1204.         
  1205.     curUndoTask = aTask;
  1206. }
  1207.  
  1208. /*--------------------------------***  UPDATEUNDO  ***----------------------------------*/
  1209. /*    
  1210. update the Undo menu item to reflect the current undo task
  1211. ----------------------------------------------------------------------------------------*/
  1212.  
  1213. void    ZApplication::UpdateUndo()
  1214. {
  1215.     Str255        undoMenuStr;
  1216.     
  1217.     if ( curUndoTask )
  1218.     {
  1219.         // a task available, so update the undo menu item to the task string.
  1220.         
  1221.         Str63        taskStr;
  1222.         
  1223.         if (curUndoTask->IsUndone())
  1224.             GetIndString( undoMenuStr, kMiscStrListID, kRedoStrIndex );
  1225.         else
  1226.             GetIndString( undoMenuStr, kMiscStrListID, kUndoStrIndex );
  1227.             
  1228.         // add the task name
  1229.         
  1230.         curUndoTask->GetTaskString( taskStr );
  1231.         ConcatPStrings( undoMenuStr, taskStr );
  1232.         
  1233.         // set the menu item to the task name
  1234.         
  1235.         gMenuBar->SetCommandText( kCmdUndo, undoMenuStr );
  1236.         
  1237.         // there is a task, but does it refer to the front window? If not,
  1238.         // then do not actually enable the command.
  1239.  
  1240.         if ((curUndoTask->GetUndoTarget() == GetFrontWindow()) &&
  1241.             (curUndoTask->GetUndoTarget() != NULL))
  1242.             gMenuBar->EnableCommand( kCmdUndo );
  1243.     }
  1244.     else
  1245.     {
  1246.         // if no task, just show a dimmed "Can't Undo"
  1247.         
  1248.         gMenuBar->SetCommandText( kCmdUndo, kMiscStrListID, kCantUndoStrIndex );
  1249.     }
  1250. }
  1251.  
  1252.  
  1253. /*---------------------------------***  DOSUSPEND  ***----------------------------------*/
  1254. /*    
  1255. send a suspend message
  1256. ----------------------------------------------------------------------------------------*/
  1257.  
  1258. void        ZApplication::DoSuspend()
  1259. {
  1260.     SendMessage( msgApplicationSuspending, 0 );
  1261.  
  1262.     gWindowManager->Suspend();
  1263. }
  1264.  
  1265.  
  1266. /*---------------------------------***  DORESUME  ***-----------------------------------*/
  1267. /*    
  1268. send a resume message
  1269. ----------------------------------------------------------------------------------------*/
  1270.  
  1271. void        ZApplication::DoResume()
  1272. {
  1273.     gWindowManager->Resume();
  1274.     
  1275.     SendMessage( msgApplicationResuming, 0 );
  1276. }
  1277.  
  1278.  
  1279.  
  1280. #pragma mark -
  1281. /*-------------------------------***  INITMENUBAR  ***----------------------------------*/
  1282. /*    
  1283. set up the menubar object for managing the main menus
  1284. ----------------------------------------------------------------------------------------*/
  1285.  
  1286. void        ZApplication::InitMenuBar()
  1287. {
  1288.     // installs the menu bar. By default, we just install 'MBAR' ID = 128, which means you
  1289.     // don't need to override this to get other menus- just create the resources you want.
  1290.     
  1291.     FailNIL( gMenuBar = new ZMenuBar( kStdMenubarID ));
  1292.  
  1293.     gMenuBar->InitMenuBar();
  1294. }
  1295.  
  1296.  
  1297. /*---------------------------***  MOUSENOTINANYWINDOW  ***------------------------------*/
  1298. /*    
  1299. the mouse is not over any window. By default this just sets the default cursor shape, but
  1300. you can override this to get informed if you are interested in this fact.
  1301. ----------------------------------------------------------------------------------------*/
  1302.  
  1303. void    ZApplication::MouseNotInAnyWindow( const Point globalMouse )
  1304. {
  1305.     ResumeCursorAnimation();
  1306.     SetCursorShape( 0 );
  1307. }
  1308.  
  1309.  
  1310. /*----------------------------***  HANDLEMBARHIDING  ***--------------------------------*/
  1311. /*    
  1312.  
  1313. deal with the menubar hiding for auto hiding feature
  1314. ----------------------------------------------------------------------------------------*/
  1315.  
  1316. void    ZApplication::HandleMBarHiding( const Point globalPt )
  1317. {
  1318. #if _AUTO_MBAR_HIDING
  1319.     
  1320.     if ( ! InBackground())
  1321.         gMenuBar->ShowHideMenuBar( MBAR_HIDE_MOUSEAWARE, globalPt );
  1322.     
  1323. #endif
  1324. }
  1325.  
  1326.  
  1327. /*--------------------------------***  MAKECLIPBOARD  ***-------------------------------*/
  1328. /*    
  1329.  
  1330. Make the clipboard object. By default, this is a ZClipboard.
  1331. ----------------------------------------------------------------------------------------*/
  1332.  
  1333. void        ZApplication::MakeClipboard()
  1334. {
  1335.     FailNIL( gClipboard = new ZClipboard());
  1336. }
  1337.  
  1338.  
  1339. /*---------------------------------***  MAKEHELPERS  ***--------------------------------*/
  1340. /*    
  1341.  
  1342. Make the helper objects. The standard helpers are the event handler, the window manager
  1343. and the applescript handlers
  1344. ----------------------------------------------------------------------------------------*/
  1345.  
  1346.  
  1347. void        ZApplication::MakeHelpers()
  1348. {
  1349.     // make the event handler
  1350.     
  1351.     FailNIL( zEH = new ZEventHandler());
  1352.     
  1353.     // make the window manager for handling floating windows, etc.
  1354.     
  1355.     FailNIL( gWindowManager = new ZWindowManager());
  1356.     
  1357.     // install handlers for the four required events
  1358.     
  1359.     zEH->InstallApplescriptHandlers();        
  1360. }
  1361.  
  1362.  
  1363. /*--------------------------------***  MAKEPRINTER  ***---------------------------------*/
  1364. /*    
  1365.  
  1366. creates a new printer object for handling the print commands
  1367.  
  1368. ----------------------------------------------------------------------------------------*/
  1369.  
  1370. void        ZApplication::MakePrinter()
  1371. {
  1372.     #if PRINTING_ON
  1373.     
  1374.     try
  1375.     {
  1376.         FailNIL( itsPrinter = new ZPrinter());
  1377.     }
  1378.     catch( OSErr err )
  1379.     {
  1380.         itsPrinter = NULL;
  1381.         
  1382.         // note, to not have a printer is not fatal- in this case we carry on,
  1383.         // but print commands will be greyed out. This may happen if no printer
  1384.         // driver is selected in the chooser.
  1385.     }
  1386.     #endif
  1387. }
  1388.  
  1389. #pragma mark -
  1390.  
  1391. /*----------------------------***  MAKENEWWINDOWTYPE  ***-------------------------------*/
  1392. /*    
  1393.  
  1394. creates a new window object and initialises it. It does not show it yet. Normally you will
  1395. override this method to create your own useful kinds of windows. However, even if you don't
  1396. you'll still get a plain window that works.
  1397. ----------------------------------------------------------------------------------------*/
  1398.  
  1399. ZWindow*        ZApplication::MakeNewWindowType( OSType aType )
  1400. {
  1401.     ZWindow* aWindow;
  1402.     
  1403. #ifdef USER_DEFAULT_WINDOW_TYPE
  1404.     FailNIL( aWindow = new USER_DEFAULT_WINDOW_TYPE( this,  kUntitledWindowID ));
  1405. #else
  1406.     FailNIL( aWindow = new ZWindow( this,  kUntitledWindowID ));
  1407. #endif    
  1408.  
  1409.     try
  1410.     {
  1411.         aWindow->InitZWindow();
  1412.     }
  1413.     catch( OSErr err )
  1414.     {
  1415.         ForgetObject( aWindow );
  1416.         
  1417.         throw err;
  1418.     }
  1419.     
  1420.     return aWindow;
  1421. }
  1422.  
  1423.  
  1424. /*----------------------------***  OPENNEWWINDOWTYPE  ***-------------------------------*/
  1425. /*    
  1426. create a new window object of the requisite type.
  1427. ----------------------------------------------------------------------------------------*/
  1428.  
  1429. ZWindow*    ZApplication::OpenNewWindowType( OSType aType )
  1430. {
  1431.     ZWindow*    theWindow;
  1432.     
  1433.     gMenuBar->SetZoomSourceToCommand( kCmdNew );
  1434.  
  1435.     theWindow = MakeNewWindowType( aType );
  1436.     
  1437.     if ( theWindow )
  1438.     {
  1439.         theWindow->Place();
  1440.         theWindow->Select();
  1441.     }
  1442.     
  1443.     return theWindow;
  1444. }
  1445.  
  1446.  
  1447. /*---------------------------------***  CLOSEALL  ***-----------------------------------*/
  1448. /*    
  1449.  
  1450. closes all of the application's windows. If one refuses to close, this will abort a Quit.
  1451. This iterates backwards through its underlings list looking for windows, rather than
  1452. relying on the window lists, since windows will also close their own underling windows so
  1453. the whole commander tree is cleaned up properly. If your app organises things differently,
  1454. you may need to override this.
  1455. ----------------------------------------------------------------------------------------*/
  1456.  
  1457. void    ZApplication::CloseAll( Boolean closeFloaters )
  1458. {
  1459.     long        i;
  1460.     ZWindow*    aWindow;
  1461.     
  1462.     if ( itsUnderlings )
  1463.     {
  1464.         i = itsUnderlings->CountItems();
  1465.         
  1466.         while( i )
  1467.         {
  1468.             aWindow = dynamic_cast<ZWindow*>( itsUnderlings->GetObject( i-- ));
  1469.             
  1470.             if ( aWindow )
  1471.             { 
  1472.                 if ( phase == kQuitting )
  1473.                 {
  1474.                     if ( ! aWindow->Close( phase ))
  1475.                     {
  1476.                         phase = kRunning;
  1477.                         done = FALSE;
  1478.                         break;
  1479.                     }
  1480.                 }
  1481.                 else
  1482.                 {
  1483.                     if (! aWindow->NoAutoClose() && ( aWindow->Floats() == closeFloaters ))
  1484.                     {
  1485.                         if ( ! aWindow->Close( phase ))
  1486.                         {
  1487.                             phase = kRunning;
  1488.                             done = FALSE;
  1489.                             break;
  1490.                         }
  1491.                     }
  1492.                 }
  1493.             }
  1494.         }
  1495.     }
  1496. }
  1497.  
  1498. /*------------------------------***  GETFRONTWINDOW  ***--------------------------------*/
  1499. /*    
  1500.  
  1501. returns the active window object, if there is one
  1502.  
  1503. ----------------------------------------------------------------------------------------*/
  1504.  
  1505. ZWindow*    ZApplication::GetFrontWindow()
  1506. {
  1507.     return ( gWindowManager->GetTopWindow());
  1508. }
  1509.  
  1510.  
  1511. /*----------------------------------***  PICKFILE  ***----------------------------------*/
  1512. /*    
  1513.  
  1514. displays the standard file dialog for selecting a file, and returns its filespec.
  1515.  
  1516. ----------------------------------------------------------------------------------------*/
  1517.  
  1518.  
  1519. Boolean        ZApplication::PickFile( FSSpec* aFile, OSType* fType )
  1520. {
  1521.     // uses standard file to choose a file to open to a window. By default, no files types
  1522.     // are added to the list, which we here interpret to mean "show all files".
  1523.  
  1524. #if _USE_NAVIGATION_SERVICES
  1525.     // using navigation services, so we need to tackle things a little differently. The result
  1526.     // from this method is the same- namely a single filespec and a type.
  1527.     
  1528.     if ( gMacInfo.hasNavigationServices )
  1529.     {
  1530.         OSErr                theErr;
  1531.         NavReplyRecord        navReply;
  1532.         NavDialogOptions    navOptions;
  1533.         Boolean                result = FALSE;
  1534.         
  1535.         FailOSErr( NavGetDefaultDialogOptions( &navOptions ));
  1536.         GetName( navOptions.clientName );
  1537.         
  1538.         // if file list empty, allow "all files"
  1539.         
  1540.         if ((*itsFileTypes)->osTypeCount == 0 )
  1541.             navOptions.dialogOptionFlags |= kNavAllFilesInPopup;
  1542.         
  1543.         // only permit one selection here:
  1544.         
  1545.         navOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles;
  1546.         gWindowManager->DeactivateForDialog( -1, FALSE );
  1547.         StopCursorAnimation();
  1548.         
  1549.         theErr = NavGetFile( NULL,
  1550.                              &navReply,
  1551.                              &navOptions,
  1552.                              gNavEventHandler,
  1553.                              NULL,
  1554.                              NULL,
  1555.                              (NavTypeListHandle) itsFileTypes,
  1556.                              (NavCallBackUserData) this );
  1557.                              
  1558.         gWindowManager->Activate();
  1559.                                 
  1560.         // extract info. Since we only allowed 1 selection, this will be the first item:
  1561.         
  1562.         if (( theErr == noErr ) && navReply.validRecord )
  1563.         {
  1564.             AEDesc    specDesc;
  1565.             FInfo    fi;
  1566.             
  1567.             FailOSErr( AEGetNthDesc( &navReply.selection, 1, typeFSS, NULL, &specDesc ));
  1568.             
  1569.             BlockMoveData( *specDesc.dataHandle, aFile, sizeof( FSSpec ));
  1570.                 
  1571.             // to get the type we need to do a FsGetFInfo:
  1572.                 
  1573.             FSpGetFInfo( aFile, &fi );
  1574.             *fType = fi.fdType;
  1575.         
  1576.             result = TRUE;
  1577.         }
  1578.         else
  1579.             result = FALSE;
  1580.             
  1581.         FailOSErr( NavDisposeReply( &navReply ));
  1582.         
  1583.         return result;
  1584.     }
  1585.     else
  1586.     {
  1587. #endif
  1588.  
  1589.     StandardFileReply    aReply;
  1590.     OSType*                listPtr;
  1591.     short                numTypes;
  1592.     
  1593.     HLock((Handle) itsFileTypes );
  1594.     numTypes = (*itsFileTypes )->osTypeCount;
  1595.     listPtr = &(*itsFileTypes)->osType[0];
  1596.     
  1597.     // if no types in the list, show all of them
  1598.     
  1599.     if( numTypes <= 0 )
  1600.         numTypes = -1;
  1601.     
  1602.     StopCursorAnimation();
  1603.     gWindowManager->DeactivateForDialog( sfGetDialogID );
  1604.     
  1605.     // display the dialog
  1606.     StandardGetFile( NULL, numTypes, listPtr, &aReply );
  1607.     HUnlock((Handle) itsFileTypes );
  1608.     
  1609.     gWindowManager->Activate();
  1610.     
  1611.     if ( aReply.sfGood )
  1612.     {
  1613.         *aFile = aReply.sfFile;
  1614.         *fType = aReply.sfType;
  1615.         return TRUE;
  1616.     }
  1617.     else
  1618.         return FALSE;
  1619.  
  1620. #if _USE_NAVIGATION_SERVICES
  1621.     }
  1622. #endif
  1623. }
  1624.  
  1625.  
  1626. /*----------------------------------***  OPENFILE  ***----------------------------------*/
  1627. /*    
  1628.  
  1629. creates a new window and asks it to open the file. It then shows the window and activates it.
  1630. If your application doesn't have a classic "document" interface, but e.g. simply processes
  1631. files dropped on the application, you can override this method to process the files. It will
  1632. be called once for each file dropped on the application that we know how to open.
  1633. ----------------------------------------------------------------------------------------*/
  1634.  
  1635. ZWindow*    ZApplication::OpenFile( const FSSpec& aFile, const OSType fType, Boolean isStationery )
  1636. {
  1637.     // opens the file into a new window. This is equivalent to OpenNewWindow, but
  1638.     // for when the user chose a file with the Open command
  1639.     
  1640.     ZWindow*    aWindow = NULL;
  1641.     
  1642.     SetWatchCursor();
  1643.     aWindow = MakeNewWindowType( fType );
  1644.     
  1645.     // window created, so ask it to open the chosen file
  1646.     
  1647.     if ( aWindow )
  1648.     {
  1649.         try
  1650.         {
  1651.             aWindow->SetFile( aFile );
  1652.             aWindow->OpenFile( fType, isStationery );
  1653.             aWindow->Place();
  1654.             aWindow->Select();
  1655.         }
  1656.         catch( OSErr err )
  1657.         {
  1658.             ForgetObject( aWindow );
  1659.             throw err;
  1660.         }
  1661.     }
  1662.     
  1663.     return aWindow;
  1664. }
  1665.  
  1666.  
  1667. /*--------------------------------***  ADDFILETYPE  ***---------------------------------*/
  1668. /*    
  1669. adds <aType> to the list of types this application will show in the Open dialog. You can
  1670. call this for each type your application can open. This ignores duplicates.
  1671. -----------------------------------------------------------------------------------------*/
  1672.  
  1673. void        ZApplication::AddFileType( const OSType aType )
  1674. {
  1675.     // adds the file type to the list of types, if not already there
  1676.     
  1677.     short    nTypes, i;
  1678.     
  1679.     nTypes = (*itsFileTypes)->osTypeCount;
  1680.     
  1681.     // check that the file type we are adding is unique in the list
  1682.     
  1683.     for ( i = 0; i < nTypes; i++ )
  1684.     {
  1685.         if ((*itsFileTypes)->osType[i] == aType )
  1686.             return;
  1687.     }
  1688.     
  1689.     // if we are still here, type is unique, so append it
  1690.     // first grow the handle
  1691.     
  1692.     SetHandleSize((Handle) itsFileTypes, GetHandleSize((Handle) itsFileTypes ) + sizeof( OSType ));
  1693.     FailMemError();
  1694.     
  1695.     // set the new entry
  1696.     
  1697.     (*itsFileTypes)->osType[ nTypes ] = aType;
  1698.     (*itsFileTypes)->osTypeCount++;
  1699. }
  1700.  
  1701.  
  1702. /*------------------------------***  CANOPENFILETYPE  ***--------------------------------*/
  1703. /*
  1704. return TRUE if this application can open files of the given type. The default method
  1705. determines if the type is in the fileType list or not. If the list is empty, this always
  1706. return TRUE.    
  1707. -----------------------------------------------------------------------------------------*/
  1708.  
  1709. Boolean        ZApplication::CanOpenFileType( const OSType aType )
  1710. {
  1711.     short    nTypes, i;
  1712.     
  1713.     nTypes = (*itsFileTypes)->osTypeCount;
  1714.     
  1715.     if ( nTypes > 0 )
  1716.     {
  1717.         for ( i = 0; i < nTypes; i++ )
  1718.         {
  1719.             if ( (*itsFileTypes)->osType[i] == aType )
  1720.                 return TRUE;
  1721.         }
  1722.         
  1723.         return FALSE;
  1724.     }
  1725.     else
  1726.         return TRUE;
  1727. }
  1728.  
  1729.  
  1730. /*------------------------------***  REGISTERCLASSES  ***-------------------------------*/
  1731. /*    
  1732. in order to use persistent objects, classes must be registered. You only need to register
  1733. classes that you will want to create from a stream. By default this registers those
  1734. required classes that could be constructed from a stream- override this to extend the
  1735. range of classes, but always call the inherited method.
  1736. ----------------------------------------------------------------------------------------*/
  1737.  
  1738. void        ZApplication::RegisterClasses()
  1739. {
  1740. #if _MACZOOP_STREAMS
  1741.  
  1742.     FailNIL( gClasses );
  1743.     
  1744.     REGISTERCLASS( ZComrade );
  1745.     REGISTERCLASS( ZCommander );
  1746.     REGISTERCLASS( ZArray );
  1747.     REGISTERCLASS( ZWindow );
  1748.     REGISTERCLASS( ZApplication );
  1749.     REGISTERCLASS( ZObjectList );
  1750.  
  1751. #endif
  1752. }
  1753.  
  1754.  
  1755.  
  1756. #pragma mark -
  1757. /*---------------------------------***  ZGROWFUNC  ***----------------------------------*/
  1758. /*    
  1759.  
  1760. memory manager callback proc.
  1761. ----------------------------------------------------------------------------------------*/
  1762.  
  1763. static pascal long ZGrowFunc( Size bytesShort )
  1764. {
  1765.     Boolean bytesFreed;
  1766.     
  1767.     // call application object to free some memory
  1768.  
  1769.     try
  1770.     {
  1771.         bytesFreed = gApplication->MemoryShortage( bytesShort );
  1772.     }
  1773.     catch(...)
  1774.     {
  1775.         bytesFreed = 0;
  1776.         
  1777.         // do NOT proagate any exception, since we are within a toolbox callback
  1778.     }
  1779.     
  1780.     return bytesFreed;
  1781. }
  1782.  
  1783.  
  1784. /*------------------------------***  RUNAPPLICATION  ***--------------------------------*/
  1785. /*    
  1786. standard function to run the application. Your main() function must make the relevant
  1787. ZApplication object, assign it to gApplication, then call this. Note that this will happen
  1788. automagically as long as you define APP_CLASS_NAME to be the classname of your application
  1789. object. This definition is set up in <ProjectSettings.h>
  1790. ----------------------------------------------------------------------------------------*/
  1791.  
  1792. void    RunApplication()
  1793. {
  1794.     if (gApplication)
  1795.     {    
  1796.         try
  1797.         {
  1798.             gApplication->InitMacZoop();            // initialise the whole kaboodle. This is
  1799.                                                     // NOT done by the constructor since you might
  1800.                                                     // want to override the initialisation.
  1801.         }
  1802.         catch( OSErr err )
  1803.         {
  1804.             // if an exception occurs during startup, the application cannot run, since
  1805.             // everything must be properly built and in place before handling events. In this
  1806.             // case we display a fatal alert message and exit.
  1807.  
  1808.             Str31    appName, errStr;
  1809.             
  1810.             gApplication->GetName( appName );
  1811.             NumToString( err, errStr );
  1812.             ParamText( appName, errStr, NULL, NULL );
  1813.             
  1814.             StopCursorAnimation();
  1815.             (void) Alert( kFatalStartupErrAlertID, NULL );
  1816.             ExitToShell();
  1817.         }
  1818.  
  1819.         // initialisation is now complete, so we can go ahead and run the thing
  1820.         
  1821.         do
  1822.         {
  1823.             gApplication->Run();                    // run the application until the user quits
  1824.         }
  1825.         while (! gApplication->Quit());                // try to quit
  1826.     }
  1827. }
  1828.  
  1829.  
  1830.  
  1831. #if _USE_NAVIGATION_SERVICES
  1832. pascal void    ZNavEventCallback(     NavEventCallbackMessage cbMessage,
  1833.                                 NavCBRecPtr    cbParams,
  1834.                                 NavCallBackUserData    cbData )
  1835. {
  1836.     GrafPtr        savePort;
  1837.     
  1838.     switch ( cbMessage )
  1839.     {
  1840.         case kNavCBEvent:
  1841.             GetPort( &savePort );
  1842.             
  1843.         #if UNIVERSAL_INTERFACES_VERSION < 0x0320
  1844.             if ( cbParams->eventData.event->what == updateEvt   ||
  1845.                  cbParams->eventData.event->what == activateEvt ||
  1846.                  cbParams->eventData.event->what == nullEvent )
  1847.                 gApplication->Process1Event( cbParams->eventData.event );
  1848.         #else
  1849.             if ( cbParams->eventData.eventDataParms.event->what == updateEvt   ||
  1850.                  cbParams->eventData.eventDataParms.event->what == activateEvt ||
  1851.                  cbParams->eventData.eventDataParms.event->what == nullEvent )
  1852.                 gApplication->Process1Event( cbParams->eventData.eventDataParms.event );
  1853.         #endif
  1854.             
  1855.             SetPort( savePort );
  1856.             break;
  1857.             
  1858.         default:
  1859.             break;
  1860.     
  1861.     
  1862.     }
  1863. }
  1864.  
  1865. #endif
  1866.